---@diagnostic disable: lowercase-global, undefined-global
local version = "1.0.2"
local required_ts_version = "1.1.5"    -- 需要的ts.so版本
local required_tslib_version = "1.4.1"  -- 需要的TSLib版本

-- 全局变量
local width, height = 0, 0  -- 初始化屏幕宽高变量
local currentZoneIndex = 1  -- 当前安全区索引
local currentDungeonIndex = 1  -- 当前副本索引
local currentSubDungeonIndex = 1  -- 当前子副本索引

-- 副本选择UI的位置配置（四个副本选项的坐标）
local dungeonSelectPositions = {
    {x = 0, y = 0},  -- 第1个副本位置，默认为0，会在UI中配置
    {x = 0, y = 0},  -- 第2个副本位置
    {x = 0, y = 0},  -- 第3个副本位置
    {x = 0, y = 0}   -- 第4个副本位置
}

-- 打印日志函数
function log(text)
    local timeStr = os.date("%Y-%m-%d %H:%M:%S")
    local logText = "[" .. timeStr .. "] " .. text
    nLog(logText)        -- 写入日志文件
end

-- 引入触动精灵基础库
local ts = require("TSLib")  -- 触动精灵函数库
local sz = require("sz")
local json = sz.json

-- 记录Boss击杀时间的表
local bossKillTimes = {}

-- 战斗持续时间（从配置获取）
local fightDuration = 300 -- 默认5分钟

-- 屏幕区域定义
local refreshTimeRegion = {left = 0, top = 0, right = 0, bottom = 0} -- 需要根据实际游戏截图位置修改

-- 通过OCR识别Boss刷新倒计时
function recognizeRefreshTime()
    nLog("尝试识别Boss刷新倒计时")
    
    -- 截取屏幕中刷新时间区域
    local imgFile = userPath().."/refresh_time.png"
    snapshot(refreshTimeRegion.left, refreshTimeRegion.top, refreshTimeRegion.right, refreshTimeRegion.bottom, imgFile)
    
    -- 使用OCR识别文字
    local text = ocrText(imgFile, 1) -- 1为简体中文
    nLog("OCR识别结果: " .. text)
    
    -- 删除临时截图
    os.remove(imgFile)
    
    -- 解析识别结果，提取倒计时
    local hours, minutes = parseRefreshTime(text)
    
    if hours and minutes then
        -- 计算距离刷新的时间（秒）
        local secondsLeft = hours * 3600 + minutes * 60
        nLog("解析结果: 剩余刷新时间 " .. hours .. "小时" .. minutes .. "分钟")
        return secondsLeft
    else
        nLog("无法解析刷新时间")
        return nil
    end
end

-- 解析倒计时文本
function parseRefreshTime(text)
    -- 可能的格式：
    -- "刷新倒计时：01小时30分钟"
    -- "Boss刷新：1小时30分"
    -- "剩余：1h30m"
    
    -- 尝试匹配多种可能的格式
    local hours, minutes = text:match("(%d+)小时(%d+)分钟")
    
    if not hours then
        hours, minutes = text:match("(%d+)小时(%d+)分")
    end
    
    if not hours then
        hours, minutes = text:match("(%d+)h(%d+)m")
    end
    
    if not hours then
        -- 可能还有其他格式，根据实际情况添加
        return nil, nil
    end
    
    return tonumber(hours), tonumber(minutes)
end

-- 计算下次可进入时间
function getNextEntryTime(bossName)
    if bossKillTimes[bossName] then
        local nextTime = bossKillTimes[bossName] + 3600 -- 1小时后
        return nextTime
    end
    return 0 -- 如果没有记录，表示可以立即进入
end

-- 根据OCR结果更新Boss刷新时间
function updateBossTimeFromOCR(bossName)
    local secondsLeft = recognizeRefreshTime()
    
    if secondsLeft then
        -- 根据倒计时计算确切的刷新时间点
        local refreshTime = os.time() + secondsLeft
        
        -- 向前推算杀死时间（Boss刷新间隔为1小时）
        local killTime = refreshTime - 3600
        
        -- 更新记录
        bossKillTimes[bossName] = killTime
        
        nLog("根据OCR结果更新Boss[" .. bossName .. "]击杀时间: " .. os.date("%Y-%m-%d %H:%M:%S", killTime))
        nLog("预计下次刷新时间: " .. os.date("%Y-%m-%d %H:%M:%S", refreshTime))
        
        return true
    end
    
    return false
end

-- 初始化Boss时间信息
function initBossTime(bossName)
    -- 先尝试从OCR获取
    local success = updateBossTimeFromOCR(bossName)
    
    if not success then
        -- 如果OCR失败，则假设可以立即进入
        nLog("无法通过OCR获取Boss[" .. bossName .. "]时间，假设可以立即进入")
        bossKillTimes[bossName] = 0
    end
end

-- 移动到指定坐标
function moveToPosition(x, y)
    nLog("移动到坐标: " .. x .. "," .. y)
    tap(x, y)
    mSleep(1000) -- 等待移动
end

-- 与NPC交互
function talkToNPC(x, y)
    nLog("与NPC交互: " .. x .. "," .. y)
    tap(x, y)
    mSleep(1000)
    -- 点击对话选项 (假设对话选项在固定位置)
    tap(width/2, height*0.7)
    mSleep(500)
end

-- 选择副本
function selectDungeon(subDungeonIndex)
    if subDungeonIndex < 1 or subDungeonIndex > 4 then
        nLog("错误: 副本索引超出范围: " .. subDungeonIndex)
        return false
    end
    
    local pos = dungeonSelectPositions[subDungeonIndex]
    if not pos or pos.x == 0 or pos.y == 0 then
        nLog("错误: 副本选择位置未正确配置")
        return false
    end
    
    nLog("选择第" .. subDungeonIndex .. "个副本, 坐标: " .. pos.x .. "," .. pos.y)
    tap(pos.x, pos.y)
    mSleep(1000)
    return true
end

-- 进入副本
function enterDungeon(dungeonIndex, subDungeonIndex)
    nLog("进入第" .. dungeonIndex .. "个NPC的第" .. subDungeonIndex .. "个副本")
    
    -- 选择对应的副本
    if not selectDungeon(subDungeonIndex) then
        return false
    end
    
    -- 点击进入副本按钮 (位置可能需要根据实际情况调整)
    tap(width/2, height*0.8)
    mSleep(3000) -- 等待加载
    return true
end

-- 打怪
function fightMonsters(duration)
    nLog("开始打怪，持续" .. duration .. "秒")
    local startTime = os.time()
    
    while os.time() - startTime < duration do
        -- 这里可以添加自动战斗的逻辑
        -- 例如寻找怪物、使用技能等
        
        -- 假设技能按钮在屏幕底部
        tap(width*0.2, height*0.9) -- 技能1
        mSleep(500)
        tap(width*0.35, height*0.9) -- 技能2
        mSleep(500)
        tap(width*0.5, height*0.9) -- 技能3
        mSleep(500)
        
        -- 检测是否有Boss出现 (这里需要根据游戏实际情况实现)
        local hasBoss = checkForBoss()
        if hasBoss then
            nLog("发现Boss，开始挑战")
            fightBoss()
            break
        end
    end
end

-- 检测Boss
function checkForBoss()
    -- 这里需要实现Boss检测逻辑
    -- 可以使用触动精灵的找图或找色功能
    
    -- 示例代码 (需要替换为实际的Boss检测逻辑)
    return false
end

-- 挑战Boss
function fightBoss()
    nLog("开始挑战Boss")
    
    -- 使用技能打Boss
    for i = 1, 10 do
        tap(width*0.2, height*0.9) -- 技能1
        mSleep(300)
        tap(width*0.35, height*0.9) -- 技能2
        mSleep(300)
        tap(width*0.5, height*0.9) -- 技能3
        mSleep(300)
        tap(width*0.65, height*0.9) -- 技能4
        mSleep(300)
    end
    
    -- 检查索引有效性
    if safeZones and currentZoneIndex and currentDungeonIndex and currentSubDungeonIndex and
       safeZones[currentZoneIndex] and 
       safeZones[currentZoneIndex].dungeons and 
       safeZones[currentZoneIndex].dungeons[(currentDungeonIndex-1)*4 + currentSubDungeonIndex] then
        
        -- 记录当前Boss击杀时间
        local currentMap = safeZones[currentZoneIndex].dungeons[(currentDungeonIndex-1)*4 + currentSubDungeonIndex]
        bossKillTimes[currentMap] = os.time()
        nLog("记录Boss击杀时间: " .. os.date("%Y-%m-%d %H:%M:%S", bossKillTimes[currentMap]))
        nLog("下次可进入时间: " .. os.date("%Y-%m-%d %H:%M:%S", bossKillTimes[currentMap] + 3600))
    else
        nLog("警告: 无法记录Boss击杀时间，索引无效")
    end
    
    -- 等待战斗结束
    mSleep(5000)
    
    -- 点击继续/离开 (位置可能需要根据实际情况调整)
    tap(width/2, height*0.7)
    mSleep(2000)
end

-- 返回安全区
function returnToSafeZone()
    nLog("返回安全区")
    -- 点击返回按钮 (位置可能需要根据实际情况调整)
    tap(width*0.1, height*0.1)
    mSleep(3000) -- 等待加载
end

-- 切换安全区
function switchSafeZone(index)
    local zone = safeZones[index]
    nLog("切换到安全区: " .. zone.name)
    
    -- 这里实现切换安全区的逻辑
    -- 可能需要打开地图，点击安全区位置等
    
    -- 示例: 打开地图
    tap(width*0.9, height*0.1) -- 假设地图按钮在右上角
    mSleep(1000)
    
    -- 点击目标安全区
    tap(zone.mapX, zone.mapY)
    mSleep(5000) -- 等待加载
end

-- 检查副本是否可进入
function checkDungeonAvailable(dungeonName)
    -- 检查Boss刷新时间
    local nextEntryTime = getNextEntryTime(dungeonName)
    local currentTime = os.time()
    
    if currentTime >= nextEntryTime then
        return true
    else
        local waitTime = nextEntryTime - currentTime
        nLog("副本 " .. dungeonName .. " 的Boss还未刷新，需等待 " .. math.floor(waitTime/60) .. " 分钟")
        return false
    end
end

-- 检查副本刷新状态并更新时间
function checkAndUpdateBossRefreshTime(dungeonName)
    -- 在无法进入副本时，尝试更新Boss刷新时间信息
    nLog("检查副本[" .. dungeonName .. "]刷新状态")
    
    -- 打开副本信息界面 (这里需要根据实际游戏操作来实现)
    -- 例如点击NPC后选择查看副本信息而不是进入
    
    -- 等待界面加载
    mSleep(1000)
    
    -- 尝试通过OCR更新Boss刷新时间
    local success = updateBossTimeFromOCR(dungeonName)
    
    -- 关闭副本信息界面
    tap(width*0.9, height*0.1) -- 假设关闭按钮在右上角
    mSleep(500)
    
    return success
end

-- 主循环
function mainLoop()
    -- 屏幕尺寸在main函数中已初始化，这里只检查一下
    if width == 0 or height == 0 then
        width, height = getScreenSize()
        nLog("在mainLoop中重新获取屏幕分辨率: " .. width .. "x" .. height)
    end
    
    -- 仅当OCR识别区域未设置时（全为0或null）才应用默认值
    if refreshTimeRegion.left == 0 and refreshTimeRegion.top == 0 and 
       refreshTimeRegion.right == 0 and refreshTimeRegion.bottom == 0 then
        nLog("使用基于屏幕分辨率的默认OCR识别区域")
        refreshTimeRegion.left = width * 0.4
        refreshTimeRegion.top = height * 0.4
        refreshTimeRegion.right = width * 0.8
        refreshTimeRegion.bottom = height * 0.5
    else
        nLog("使用用户配置的OCR识别区域: " .. 
            "left=" .. refreshTimeRegion.left .. 
            ", top=" .. refreshTimeRegion.top .. 
            ", right=" .. refreshTimeRegion.right .. 
            ", bottom=" .. refreshTimeRegion.bottom)
    end
    
    currentZoneIndex = 1
    
    while true do
        -- 检查是否需要切换安全区
        if currentZoneIndex > #safeZones then
            currentZoneIndex = 1
            nLog("已完成所有安全区，重新开始循环")
        end
        
        -- 切换到当前安全区
        switchSafeZone(currentZoneIndex)
        
        -- 遍历当前安全区的所有副本
        for i, npc in ipairs(safeZones[currentZoneIndex].npcs) do
            currentDungeonIndex = i
            
            -- 与NPC交互
            talkToNPC(npc.x, npc.y)
            
            -- 遍历该NPC的所有副本
            for j = 1, 4 do
                currentSubDungeonIndex = j
                local dungeonName = safeZones[currentZoneIndex].dungeons[(i-1)*4 + j]
                
                if dungeonName then
                    -- 如果没有此Boss记录，先尝试获取
                    if not bossKillTimes[dungeonName] then
                        initBossTime(dungeonName)
                    end
                    
                    -- 检查副本是否可进入
                    if checkDungeonAvailable(dungeonName) then
                        nLog("开始处理副本: " .. dungeonName)
                        
                        -- 进入副本
                        if enterDungeon(i, j) then
                            -- 打怪
                            fightMonsters(fightDuration) -- 使用配置的战斗时间
                            
                            -- 返回安全区
                            returnToSafeZone()
                            
                            -- 如果不是最后一个副本，需要重新与NPC交互
                            if j < 4 then
                                talkToNPC(npc.x, npc.y)
                            end
                            
                            -- 休息一下
                            mSleep(2000)
                        end
                    else
                        -- 无法进入时，尝试更新Boss刷新时间信息
                        checkAndUpdateBossRefreshTime(dungeonName)
                        
                        -- 如果不是最后一个副本，需要重新与NPC交互
                        if j < 4 then
                            talkToNPC(npc.x, npc.y)
                        end
                    end
                end
            end
        end
        
        -- 切换到下一个安全区
        currentZoneIndex = currentZoneIndex + 1
        
        -- 每完成一轮循环保存一次数据
        saveBossKillTimes()
    end
end

-- UI配置
function createUIConfig()
    -- 确保已初始化屏幕尺寸
    if width == 0 or height == 0 then
        width, height = getScreenSize()
    end
    
    return {
        style = "default",
        width = width,
        height = height,
        config = "auto_farm_config.dat",
        timer = 30,
        orient = 0,
        pagetype = "multi",
        title = "自动打怪配置",
        cancelname = "取消",
        okname = "开始",
        views = {
            {
                type = "Label",
                text = "自动打怪脚本设置",
                size = 20,
                align = "center",
                color = "0,168,233"
            },
            {
                type = "Label",
                text = "OCR识别区域设置",
                size = 16,
                align = "left",
                color = "0,168,233"
            },
            {
                type = "Label",
                text = "左边界坐标",
                size = 12,
                align = "left"
            },
            {
                type = "Edit",
                id = "ocr_left",
                prompt = "左边界",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Label",
                text = "上边界坐标",
                size = 12,
                align = "left"
            },
            {
                type = "Edit",
                id = "ocr_top",
                prompt = "上边界",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Label",
                text = "右边界坐标",
                size = 12,
                align = "left"
            },
            {
                type = "Edit",
                id = "ocr_right",
                prompt = "右边界",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Label",
                text = "下边界坐标",
                size = 12,
                align = "left"
            },
            {
                type = "Edit",
                id = "ocr_bottom",
                prompt = "下边界",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Label",
                text = "副本选择位置设置",
                size = 16,
                align = "left",
                color = "0,168,233"
            },
            {
                type = "Label",
                text = "副本1位置",
                size = 12,
                align = "left"
            },
            {
                type = "Edit",
                id = "dungeon1_x",
                prompt = "X坐标",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Edit",
                id = "dungeon1_y",
                prompt = "Y坐标",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Label",
                text = "副本2位置",
                size = 12,
                align = "left"
            },
            {
                type = "Edit",
                id = "dungeon2_x",
                prompt = "X坐标",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Edit",
                id = "dungeon2_y",
                prompt = "Y坐标",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Label",
                text = "副本3位置",
                size = 12,
                align = "left"
            },
            {
                type = "Edit",
                id = "dungeon3_x",
                prompt = "X坐标",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Edit",
                id = "dungeon3_y",
                prompt = "Y坐标",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Label",
                text = "副本4位置",
                size = 12,
                align = "left"
            },
            {
                type = "Edit",
                id = "dungeon4_x",
                prompt = "X坐标",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Edit",
                id = "dungeon4_y",
                prompt = "Y坐标",
                text = "0",
                kbtype = "number"
            },
            {
                type = "Label",
                text = "安全区设置",
                size = 16,
                align = "left",
                color = "0,168,233"
            },
            {
                type = "RadioGroup",
                id = "zone1_enable",
                list = "启用,禁用",
                select = "0"
            },
            {
                type = "Edit",
                id = "zone1_name",
                prompt = "请输入安全区名称",
                text = "安全区1",
                kbtype = "ascii"
            },
            {
                type = "Edit",
                id = "zone1_mapx",
                prompt = "X坐标",
                text = "100",
                kbtype = "number"
            },
            {
                type = "Edit",
                id = "zone1_mapy",
                prompt = "Y坐标",
                text = "100",
                kbtype = "number"
            },
            {
                type = "Label",
                text = "NPC设置",
                size = 14,
                align = "left"
            },
            {
                type = "RadioGroup",
                id = "zone1_npc1_enable",
                list = "启用,禁用",
                select = "0"
            },
            {
                type = "Edit",
                id = "zone1_npc1_x",
                prompt = "X坐标",
                text = "200",
                kbtype = "number"
            },
            {
                type = "Edit",
                id = "zone1_npc1_y",
                prompt = "Y坐标",
                text = "200",
                kbtype = "number"
            },
            {
                type = "Label",
                text = "NPC1的副本设置",
                size = 12,
                align = "left"
            },
            {
                type = "Edit",
                id = "zone1_npc1_dungeon1",
                prompt = "副本1名称",
                text = "副本1-1",
                kbtype = "ascii"
            },
            {
                type = "Edit",
                id = "zone1_npc1_dungeon2",
                prompt = "副本2名称",
                text = "副本1-2",
                kbtype = "ascii"
            },
            {
                type = "Edit",
                id = "zone1_npc1_dungeon3",
                prompt = "副本3名称",
                text = "副本1-3",
                kbtype = "ascii"
            },
            {
                type = "Edit",
                id = "zone1_npc1_dungeon4",
                prompt = "副本4名称",
                text = "副本1-4",
                kbtype = "ascii"
            },
            {
                type = "Label",
                text = "战斗参数设置",
                size = 16,
                align = "left",
                color = "0,168,233"
            },
            {
                type = "Edit",
                id = "fight_duration",
                prompt = "副本内打怪时间（秒）",
                text = "300",
                kbtype = "number"
            }
        }
    }
end

-- 显示配置界面
function showConfig()
    -- 将UI配置转换为JSON字符串
    local configJson = json.encode(createUIConfig())
    nLog("UI配置: " .. configJson)
    
    -- 显示UI配置界面
    local ret, values = showUI(configJson)
    
    nLog("ret result:" .. tostring(ret))
    if ret == 1 then
        -- 解析配置数据
        safeZones = {}
        
        -- 配置副本选择位置
        for i = 1, 4 do
            local x_id = "dungeon" .. i .. "_x"
            local y_id = "dungeon" .. i .. "_y"
            
            if values[x_id] and values[y_id] then
                dungeonSelectPositions[i].x = tonumber(values[x_id]) or 0
                dungeonSelectPositions[i].y = tonumber(values[y_id]) or 0
                nLog("设置副本" .. i .. "选择位置: x=" .. 
                    dungeonSelectPositions[i].x .. ", y=" .. 
                    dungeonSelectPositions[i].y)
            end
        end
        
        -- 设置战斗时间
        if values.fight_duration then
            fightDuration = tonumber(values.fight_duration) or 300
            nLog("设置战斗时间为: " .. fightDuration .. " 秒")
        end
        
        -- 添加安全区1
        if values.zone1_enable == "0" then
            local zone = {
                name = values.zone1_name or "安全区1",
                mapX = tonumber(values.zone1_mapx) or 0,
                mapY = tonumber(values.zone1_mapy) or 0,
                npcs = {},
                dungeons = {}
            }
            
            -- 添加NPC1
            if values.zone1_npc1_enable == "0" then
                table.insert(zone.npcs, {
                    x = tonumber(values.zone1_npc1_x) or 0,
                    y = tonumber(values.zone1_npc1_y) or 0
                })
                table.insert(zone.dungeons, values.zone1_npc1_dungeon1 or "副本1-1")
                table.insert(zone.dungeons, values.zone1_npc1_dungeon2 or "副本1-2")
                table.insert(zone.dungeons, values.zone1_npc1_dungeon3 or "副本1-3")
                table.insert(zone.dungeons, values.zone1_npc1_dungeon4 or "副本1-4")
            end
            
            table.insert(safeZones, zone)
        end
        
        -- 配置OCR区域
        if values.ocr_left and values.ocr_top and values.ocr_right and values.ocr_bottom then
            refreshTimeRegion = {
                left = tonumber(values.ocr_left) or 0,
                top = tonumber(values.ocr_top) or 0,
                right = tonumber(values.ocr_right) or 0,
                bottom = tonumber(values.ocr_bottom) or 0
            }
            nLog("已设置OCR识别区域: " .. 
                "left=" .. refreshTimeRegion.left .. 
                ", top=" .. refreshTimeRegion.top .. 
                ", right=" .. refreshTimeRegion.right .. 
                ", bottom=" .. refreshTimeRegion.bottom)
        end
        
        return true
    else
        return false
    end
end

-- 保存Boss击杀时间到文件
function saveBossKillTimes()
    local file = io.open(userPath().."/boss_kill_times.txt", "w")
    if file then
        for name, time in pairs(bossKillTimes) do
            file:write(name..":"..time.."\n")
        end
        file:close()
        nLog("Boss击杀时间已保存")
    else
        nLog("无法保存Boss击杀时间")
    end
end

-- 加载Boss击杀时间从文件
function loadBossKillTimes()
    local file = io.open(userPath().."/boss_kill_times.txt", "r")
    if file then
        for line in file:lines() do
            local name, time = line:match("([^:]+):(%d+)")
            if name and time then
                bossKillTimes[name] = tonumber(time)
                nLog("加载Boss："..name.."，击杀时间："..os.date("%Y-%m-%d %H:%M:%S", tonumber(time)))
            end
        end
        file:close()
        nLog("Boss击杀时间已加载")
    else
        nLog("没有找到Boss击杀时间记录")
    end
end

-- 主函数
function main()
    -- 显示脚本信息
    nLog("自动打怪脚本 v" .. version .. " 启动")
    
    -- 初始化屏幕尺寸
    init("0", 0) -- 横屏模式
    width, height = getScreenSize()
    nLog("屏幕分辨率: " .. width .. "x" .. height)
    
    -- 加载之前的Boss击杀时间记录
    loadBossKillTimes()
    
    -- 显示配置界面
    if showConfig() then
        -- 开始主循环
        xpcall(mainLoop, function(err)
            nLog("脚本运行出错: " .. tostring(err))
            saveBossKillTimes() -- 保存数据以防止丢失
        end)
    else
        -- 用户取消配置
        nLog("用户取消了配置，脚本结束")
    end
end

-- 启动脚本
main()
   